-- 1层下，2层上电梯，
-- 计数器100模块，en=1时开始计时，记时到100停止
-------------------------------------------


-- [count100模块]

entity count100 is
    port(
        clk, en : in std_logic;
        cout : out std_logic        -- 定时溢出信号
    );
end count100;

architecture behave of count100 is
begin

    process(clk, en) 
        variable count : std_logic_vector(7 downto 0); -- 计数
    begin
        if en = '1' then
            count := (others => '0');
        elsif rising_edge(clk) then
            count := count + 1;
        end if; 

        if count < "01100100" then -- <100
            cout <= '0';        
        else
            cout <= '1';
        end if;
    end process;

end behave;


-- [状态控制模块]

entity status is
    port(
        clk, rst : in std_logic;                        -- 时钟，复位信号
        cout : in std_logic;                            -- 定时溢出信号(定时完毕)
        call : in std_logic_vector(2 downto 1);         -- 1/2楼电梯呼叫信号
        arrive : in std_logic_vector(2 downto 1);       -- 电梯到达信号
        door : out std_logic;                           -- 开关门信号，为低电平时门打开
        up : out std_logic;                             -- 上升信号
        down : out std_logic;                           -- 下降信号
        en : out std_logic                              -- 延时计数清零，使能信号
    );
end status;

architecture behave of status is
    constant CL1 : std_logic_vector(2 downto 0) := "000";   -- 1楼关门
    constant OP1 : std_logic_vector(2 downto 0) := "000";   -- 1楼开门
    constant CL2 : std_logic_vector(2 downto 0) := "000";   -- 2楼关门
    constant OP2 : std_logic_vector(2 downto 0) := "000";   -- 2楼开门
    constant UP1 : std_logic_vector(2 downto 0) := "000";   -- 1楼上升
    constant DOWN2 : std_logic_vector(2 downto 0) := "000"; -- 2楼下降
    signal control : std_logic_vector(2 downto 0);          -- 状态控制信号
begin
    door <= not control(2);
    up <= not control(1);
    down <= not control(0);

    process(clk, rst, arrive, call) begin
        if rst = '1' then
            control <= CL1;
        elsif rising_edge(clk) then
            case control is
                when CL1 => if cout = '1' then -- 计时器完成，关门完毕
                                if call(1) = '1' then
                                    control <= OP1; en <= '0';
                                elsif call(2) = '1' then
                                    control <= UP1; en <= '1';
                                else
                                    control <= CL1; en <= '1';
                                end if;
                            else
                                control <= CL1; en <= '1';
                            end if;
                when OP1 => if cout = '1' then -- 计时器完成，开门完毕
                                if call(1) = '1' then
                                    control <= OP1; en <= '1';                        
                                else
                                    control <= CL1; en <= '0';
                                end if;
                            else
                                control <= OP1; en <= '1';
                            end if;
                when UP1 => if call(2) = '1' then                                        
                                control <= CL2;                  
                            else
                                control <= UP1;
                            end if;                           
                when DOWN2 => if call(1) = '1' then
                                    control <= CL1; en <= '0';                              
                                else
                                    control <= DOWN2; en <= '1';
                                end if;                          
                when CL2 => if cout = '1' then -- 计时器完成，关门完毕
                                if call(1) = '1' then
                                    control <= DOWN2; en <= '0';
                                elsif call(2) = '1' then
                                    control <= OP2; en <= '1';
                                else
                                    control <= CL2; en <= '1';
                                end if;
                            else
                                control <= CL2; en <= '1';
                            end if;
                when OP2 => if cout = '1' then -- 计时器完成，开门完毕
                                if call(2) = '1' then
                                    control <= OP2; en <= '1';
                                else
                                    control <= CL2; en <= '1';
                                end if;
                            else
                                control <= OP2; en <= '1';
                            end if;
                when others => if arrive(1) = '1' then
                                    control <= CL1;
                                else
                                    control <= CL2;
                                end if;
            end case;
        end if; 
    end process;

end behave;


-- 【控制器】

entity lift is
    port(
        clk, rst : in std_logic;
        call, arrive : in std_logic_vector(2 downto 1);
        door : out std_logic;
        up : out std_logic;
        down : out std_logic;
    );
end lift;

architecture lift_behave of lift is
    
    component count100 is
        port(
            clk, en : in std_logic;
            cout : out std_logic
        );
    end component;

    component status is
        port(
            clk, rst : in std_logic;        
            cout : in std_logic;                      
            call : in std_logic_vector(2 downto 1); 
            arrive : in std_logic_vector(2 downto 1);  
            door : out std_logic;               
            up : out std_logic;  
            down : out std_logic;
            en : out std_logic
        );
    end component;

    signal ena, cout : std_logic;
begin

    u1 : count100 port map(clk, ena, cout);
    u2 : status port map(clk, rst, cout, call, arrive, door, up, down);

end lift_behave;

